﻿#ifndef WRWAVEPLAYBUFFER_H
#define WRWAVEPLAYBUFFER_H

#include <QMutex>
#include <QIODevice>
#include "WRWavePlayer.h"

//表示波形播放缓存。
class WRWavePlayBuffer
{
private:
    QAtomicInt m_refCnt;
    QMutex m_mutex;
    short* m_array;
    int m_total;
    int m_start;
    int m_count;
    int m_sampleRate;

    //表示数据流。
    class DataStream : public QIODevice
    {
    private:
        //数据对象。
        WRWavePlayBuffer* m_d;
        //声道信息。
        const WRWavePlayer::Channel& m_channel;

        //定义数据值结构。
        struct DVal
        {
            short l;
            short r;
        };
        //执行数据复制。
        static inline void copyData(const short* src, DVal* dst, int cnt, WRWavePlayer::Channel way)
        {
            switch (way) {
            case WRWavePlayer::DualChannel:
                for(int i = 0; i < cnt; ++i, ++src, ++dst)
                {
                    dst->l = *src;
                    dst->r = *src;
                }
                break;
            case WRWavePlayer::LeftChannel:
                for(int i = 0; i < cnt; ++i, ++src, ++dst)
                {
                    dst->l = *src;
                    dst->r = 0;
                }
                break;
            case WRWavePlayer::RightChannel:
                for(int i = 0; i < cnt; ++i, ++src, ++dst)
                {
                    dst->l = 0;
                    dst->r = *src;
                }
                break;
            }
        }

    protected:
        //读取数据。
        qint64 readData(char* data, qint64 maxlen)
        {
            //换算读取量
            int count = (int)(maxlen / sizeof(DVal));
            //读取数据量为0处理。
            if (count < 0)
            {
                if (maxlen > 0)
                {
                    memset(data, 0, maxlen);
                    return maxlen;
                }
                return 0;
            }
            //线程同步
            QMutexLocker lck(&m_d->m_mutex);
            //计算读取量
            count = m_d->m_count > count ? count : m_d->m_count;
            //存在数据量为0处理
            if (count <= 0)
            {
                count = maxlen > 32 ? 32 : maxlen;
                memset(data, 0, count);
                return count;
            }
            //执行数据复制处理
            int start = m_d->m_start + count;
            if (start > m_d->m_total)
            {
                int count1 = m_d->m_total - m_d->m_start;
                int count2 = count - count1;
                copyData(m_d->m_array + m_d->m_start, (DVal*)data, count1, m_channel);
                copyData(m_d->m_array, ((DVal*)data) + count1, count2, m_channel);
                m_d->m_count -= count;
                m_d->m_start = m_d->m_count == 0 ? 0 : count2;
            }
            else
            {
                copyData(m_d->m_array + m_d->m_start, (DVal*)data, count, m_channel);
                m_d->m_count -= count;
                m_d->m_start = m_d->m_count == 0 ? 0 : start;
            }
            return count * sizeof(DVal);
        }
        //写入数据。
        qint64 writeData(const char*, qint64)
        {
            return 0;
        }

    public:
        //初始化缓存。
        DataStream(WRWavePlayBuffer* d, const WRWavePlayer::Channel& channel)
            : m_channel(channel)
        {
            m_d = d;
        }
        //清理当前对象所占用的相关资源。
        ~DataStream()
        {
            //add code here
        }

        //获取是否到达结束位置，返回False。
        bool atEnd() const
        {
            return false;
        }
        //获取可以读取的数据量。
        qint64 bytesAvailable() const
        {
            int c = m_d->m_count;
            if (c > 0)
                return c * sizeof(DVal);
            return 32;
        }

        //获取是否可以读取行，返回False。
        bool canReadLine() const
        {
            return false;
        }
        //获取是否顺序，返回True。
        bool isSequential() const
        {
            return true;
        }

        //获取当前位置，返回0。
        qint64 pos() const
        {
            return 0;
        }
        //重置位置，返回False。
        bool reset(void)
        {
            return false;
        }
        //定位位置，返回False。
        bool seek(qint64)
        {
            return false;
        }
        //获取数据大小。
        qint64 size() const
        {
            int c = m_d->m_count;
            if (c > 0)
                return c * sizeof(DVal);
            return 32;
        }

        //等待数据可以读取。
        bool waitForReadyRead(int)
        {
            return true;
        }
    };

    //禁用复制构造函数和赋值操作符。
    Q_DISABLE_COPY(WRWavePlayBuffer)

    //清理当前对象所占用的非托管资源。
    ~WRWavePlayBuffer(void)
    {
        delete[] m_array;
    }

public:
    //初始化当前对象。
    inline explicit WRWavePlayBuffer(int sampleRate)
        : m_refCnt(1), m_mutex(QMutex::Recursive)
    {
        m_sampleRate = sampleRate;
        m_total = sampleRate * 2;
        m_array = new short[m_total];
        m_start = 0;
        m_count = 0;
    }

    //添加引用。
    inline void addRef(void)
    {
        m_refCnt.ref();
    }
    //释放引用计数，如果引用计数为0，则释放当前对象所占用的相关资源，并返回True。
    inline bool release(void)
    {
        if (!m_refCnt.deref())
        {
            delete this;
            return true;
        }
        return false;
    }

    //写入数据。
    inline void writeData(const short *buf, int len)
    {
        //线程同步
        QMutexLocker lck(&m_mutex);
        //执行写入
        if (len >= m_total)
        {
            //写入数据超过数据总量，则直接从0开始复制并设置数据量为数据总量
            memcpy(m_array, buf + (len - m_total), sizeof(short)* m_total);
            m_start = 0;
            m_count = m_total;
        }
        else
        {
            //计算写入位置
            int write = m_start + m_count;
            if (write >= m_total) write -= m_total;
            //计算尾部可写入的数据量
            int count = m_total - write;
            if (count < len)
            {
                //尾部可写入数据量小于要写入的数据量，则分两段进行写入
                memcpy(m_array + write, buf, sizeof(short) * count);
                memcpy(m_array, buf + count, sizeof(short) * (len - count));
            }
            else
            {
                //尾部空间足够，则直接写入
                memcpy(m_array + write, buf, sizeof(short) * len);
            }
            //计算数据长度
            count = m_count + len;
            if (count > m_total)
            {
                //数据长度大小数据总量，则表示头部被覆盖，需移动头部为覆盖的数据量
                m_start += count - m_total;
                if (m_start >= m_total) m_start -= m_total;
                //设置设置数据量为数据总量
                m_count = m_total;
            }
            else
            {
                //数据长度小于等于数据总量，则直接设置长度，不移动数据首位置
                m_count = count;
            }
        }
    }
    //读取数据。
    inline QIODevice* readData(const WRWavePlayer::Channel& channel)
    {
        DataStream* stream = new DataStream(this, channel);
        stream->open(QIODevice::ReadOnly);
        return stream;
    }

    //获取采样速率。
    inline int sampleRate(void) const
    {
        return m_sampleRate;
    }
};

#endif // WRWAVEPLAYBUFFER_H
